package Websites;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.swing.Timer;

import KUtilities.KLogger;

public abstract class SMSService {
	
	protected String cookie,successMsg;
	protected String host,sendURL,sendReferrer,loginURL,loginReferrer;
    protected Thread thread;
    protected ExecutorService messageSender;
    protected KLogger logger;
    protected int inQueue=0;
    protected Timer timer;
    protected ActionListener action;
    protected int expireTime;
    
	public SMSService(KLogger logger,String host){
    	cookie=null;
    	this.logger=logger;
    	this.host=host;
    	this.expireTime=15*60*1000;
    	action=new ActionListener(){
    		public void actionPerformed(ActionEvent ae){
    			new Thread(){
    				public void run(){
    					SMSService.this.logger.log("Timed Out.. Logging Out");
    	    			logout();
    	    			timer.stop();
    				}
    			}.start();
    		}
    	};
    	timer=new Timer(expireTime,action);
    }
	
	protected void setSendData(String url,String referrer,String successMsg){
		sendURL=url;
		sendReferrer=referrer;
		this.successMsg=successMsg;
	}
	
	protected void setLoginData(String url,String referrer){
		loginURL=url;
		loginReferrer=referrer;
	}
	
	protected abstract String getLoginContent(String username, String password);
	
	protected boolean isValidUsername(String username){
		if(username==null || username.length()==0 ||username.length()!=10){
    		return false;
    	}else{
            try
            {
                Long.valueOf(username);
            }catch(NumberFormatException ex)
            {
                return false;
            }
        }
		
		return true;
	}
	
	protected boolean isValidPassword(String password){
		if(password==null || password.length()==0){
    		return false;
    	}
		return true;
	}
	
	protected abstract boolean isValidLogin(HttpURLConnection loginConnection);
	
	protected abstract void grabRequirements();
	
	public String login(String username,String password){
    	if(!isValidUsername(username)){
    		return "Please, Enter a valid Username";
    	}
    	if(!isValidUsername(username)){
    		return "Please, Enter a valid Password";
    	}
    	try {
    		username=URLEncoder.encode(username, "UTF-8");
            password=URLEncoder.encode(password, "UTF-8");
            URL loginerURL=new URL(loginURL);
			HttpURLConnection loginConnection=(HttpURLConnection)loginerURL.openConnection();
			loginConnection.setDoOutput(true);
			loginConnection.setRequestProperty("Host","site3.way2sms.com");
			loginConnection.setRequestProperty("User-Agent","Mozilla/5.0 (X11; Linux x86_64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1");
			loginConnection.setRequestProperty("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
			loginConnection.setRequestProperty("Accept-Language","en-us,en;q=0.5");
			loginConnection.setRequestProperty("Accept-Encoding","gzip, deflate");
			loginConnection.setRequestProperty("Accept-Charset","ISO-8859-1,utf-8;q=0.7,*;q=0.7");
			loginConnection.setRequestProperty("Connection","keep-alive");
			loginConnection.setRequestProperty("Referer","http://site3.way2sms.com/entry.jsp");
			loginConnection.setRequestMethod("POST");
			loginConnection.setInstanceFollowRedirects(false);
			
            PrintWriter writer=new PrintWriter(loginConnection.getOutputStream());
            writer.print(getLoginContent(username,password));
            writer.flush();
            writer.close();
            
            cookie=loginConnection.getHeaderField("Set-Cookie");
            if(cookie==null||cookie.isEmpty()){
            	return "Login Error..\nCheck your Username & Password";
            }
            if(!isValidLogin(loginConnection))
            	return "Login Error..\nCheck your Username & Password";
            grabRequirements();
            logger.log(getServiceName()+": "+"Login Successful");
            timer.stop();
            timer.start();
        	return "Login Successful";
		} catch (UnsupportedEncodingException e) {
			return "Please, Enter a valid Username/Password";
		} catch (MalformedURLException e) {
			return "<html>Site has been modified<br/>Contact the developer for update</html>";
		} catch (IOException e) {
			return "<html>Connection Failed<br/>Please try Later</html>";
		}
    }
	
	protected abstract String getSendContent(String number,String message);
	
	protected String sendQuickSMS(String number,String message)
    {
		timer.stop();
        timer.start();
        URL senderURL;
        HttpURLConnection sendConnection;
        try {
        	senderURL=new URL(sendURL);
            sendConnection = (HttpURLConnection) senderURL.openConnection();
            sendConnection.setDoOutput(true);
            sendConnection.setRequestProperty("Host",host);
            sendConnection.setRequestProperty("User-Agent","Mozilla/5.0 (X11; Linux x86_64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1");
            sendConnection.setRequestProperty("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
            sendConnection.setRequestProperty("Accept-Language","en-us,en;q=0.5");
            sendConnection.setRequestProperty("Accept-Charset","ISO-8859-1,utf-8;q=0.7,*;q=0.7");
            sendConnection.setRequestProperty("Connection","keep-alive");
            sendConnection.setRequestProperty("Referer",sendReferrer);
            sendConnection.setRequestProperty("Cookie", cookie);
            sendConnection.setRequestMethod("POST");
            sendConnection.setInstanceFollowRedirects(false);

            PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(sendConnection.getOutputStream()),true);
            printWriter.print(getSendContent(number,message));
            printWriter.flush();
            printWriter.close();
            
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(sendConnection.getInputStream()));
            StringBuilder sendResult=new StringBuilder();
            String line;
            while ((line=bufferedReader.readLine()) != null)
            {
                sendResult.append(line);
                sendResult.append('\n');
            }
            bufferedReader.close();
            if(sendResult.toString().contains(successMsg))
            {
                return "Message sent to "+number+" successfully.";
            }
            
            URL location=new URL(sendConnection.getHeaderField("Location"));
			HttpURLConnection actionConnection=(HttpURLConnection)location.openConnection();
            actionConnection.setRequestProperty("Host",host);
            actionConnection.setRequestProperty("User-Agent","Mozilla/5.0 (X11; Linux x86_64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1");
            actionConnection.setRequestProperty("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
            actionConnection.setRequestProperty("Accept-Language","en-us,en;q=0.5");
            actionConnection.setRequestProperty("Accept-Charset","ISO-8859-1,utf-8;q=0.7,*;q=0.7");
            actionConnection.setRequestProperty("Connection","keep-alive");
            actionConnection.setRequestProperty("Cookie", cookie);
            actionConnection.setRequestMethod("GET");
            actionConnection.setInstanceFollowRedirects(false);
            BufferedReader actionReader=new BufferedReader(new InputStreamReader(actionConnection.getInputStream()));
            StringBuilder response =new StringBuilder();
            String temp="";
            while((temp=actionReader.readLine())!=null){
                response.append(temp+"\n");
            }
            actionReader.close();
            if(response.toString().contains(successMsg)){
                return "Message sent to "+number+" successfully.";
            }else{
            	return "Message could not send to "+number+".";
            }
            
            
        }catch (UnsupportedEncodingException ex) {
            return "Message content encoding error";
        }catch (MalformedURLException ex) {
        	return "<html>Site has been modified<br/>Contact the developer for update</html>";
        }catch (IOException ex) {
        	return "<html>Connection Failed<br/>Please try Later</html>";
        } 
    }
	
    protected String sendMessage(String number,String message)
    {
        if(number==null || number.length()!=10)
        {
            return "Enter A Valid Phone Number";
        }
        try{
            Long.valueOf(number);
            int noMessages=message.length()/(getMaxChar()+1)+1;
            ArrayList<String> temp=new ArrayList<String>();
            for(int i=1;i<=noMessages;i++){
            	logger.log(getServiceName()+": "+"Sending Message ("+i+"/"+noMessages+") to "+number+"..");
            	temp.add(sendQuickSMS(number,message.substring(0,(message.length()<getMaxChar())?message.length():getMaxChar())));
            	decrementQueue();
            	try{
            		message=message.substring(getMaxChar()+1);
            	}catch(Exception e){}
            	try{
            		Thread.sleep(250);
            	}catch(Exception e){}
            }
            boolean success=true;
            for(int i=0;i<temp.size();i++){
            	if(temp.get(i).indexOf("successfully")!=-1)
            		continue;
            	else{
            		success=false;
            		break;
            	}
            }
            if(success)
            	return "Message sent to "+number+" successfully.\n";
            else
        		return "Message could not send to "+number+".\n";
        }catch(NumberFormatException ex)
        {
            return "Enter A Valid Phone Number";
        }
    }
    
	public void sendMessages(final String numbers,final String message)
    {
    	new Thread(){
    		public void run(){
    			if(isBusy())
    				logger.log(getServiceName()+": The Message Queue is Full\nPlease Wait");
    			while(isBusy());
    			if(!isReady())
    				logger.log(getServiceName()+": Server Not Responding");
    			while(!isReady());
    	    	messageSender=Executors.newFixedThreadPool(3);
    	    	String nums[]=numbers.split(";");
    	    	addToQueue(nums.length*(message.length()/(getMaxChar()+1)+1));
    	    	String logText=inQueue+((inQueue==1)?" Message":" Messages")+" in Queue";
    	    	logger.log(getServiceName()+": "+logText);
    	    	for(final String temp:nums){
    	    		messageSender.execute(new Runnable(){
    	    			public void run(){
    	    				logger.log(getServiceName()+": "+sendMessage(temp,message));
    	    			}
    	    		});
    	    	}
    	    	messageSender.shutdown();
    		}
    	}.start();
    }
	
	public abstract boolean logout();
	
	public boolean logout(String url)
    {
    	if(cookie!=null||!cookie.isEmpty()){
	        try {
	            HttpURLConnection logoutConnection;
	            URL logoutURL;
	            logoutURL = new URL(url);
	            logoutConnection = (HttpURLConnection) logoutURL.openConnection(); 
	            logoutConnection.setRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 6.1; rv:6.0) Gecko/20100101 Firefox/6.0");
	            logoutConnection.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
	            logoutConnection.setRequestProperty("Cookie", cookie);
	            logoutConnection.setRequestMethod("GET");
	            logoutConnection.setInstanceFollowRedirects(false);
	            BufferedReader reader = new BufferedReader(new InputStreamReader(logoutConnection.getInputStream()));
	            while ((reader.readLine()) != null);
	            reader.close();
	            cookie=null;
	            logger.log(getServiceName()+": "+"Logout Successful");
	            return true;
	        } catch (Exception ex) {
	        	logger.log(getServiceName()+": "+"Failed to Logout");
	        	return false;
	        } 
    	}
    	return false;
    	
    }
	
	private boolean isReady(){
		return !thread.isAlive();
	}
	    
	private boolean isBusy(){
	   	if(messageSender==null)
	   		return false;
	   	else
	   		return !messageSender.isTerminated();
	}
	    
	public KLogger getLogger(){
	   	return logger;
	}
	    
	public boolean isLoggedIn(){
	   	if(cookie==null)
	   		return false;
	   	else
	   		return true;
	}
	
	public abstract String getServiceName();

	public abstract int getMaxChar();
	
	private synchronized void addToQueue(int value){
		inQueue+=value;
	}
		
	private synchronized void decrementQueue(){
		inQueue--;
	}
}
